#include "util.h"

namespace util
{
	CCamera::CCamera()
	{
		reset();
	}
	CCamera::~CCamera()
	{
		reset();
	}
	void CCamera::perspective(float fov, float aspect, float znear, float zfar)
	{
		float w, h;
		h = tanf(fov / 360 * PI) * znear;
		w = h * aspect;
		glFrustum(-w, w, -h, h, znear, zfar);
	}
	void CCamera::lookat(float eyex, float eyey, float eyez,
						 float centerx, float centery, float centerz,
						 float upx, float upy, float upz)
	{
		float m[16];
		float x[3], y[3], z[3];
		float mag;
		
		// build and normalize Z vector
		z[0] = eyex - centerx;
		z[1] = eyey - centery;
		z[2] = eyez - centerz;
		mag = sqrtf(z[0] * z[0] + z[1]*z[1] + z[2]*z[2]);
		if (mag)
		{
			z[0] /= mag;
			z[1] /= mag;
			z[2] /= mag;
		}
		
		// Y vector
		y[0] = upx;
		y[1] = upy;
		y[2] = upz;

		// X vector = Y cross Z
		x[0] =  y[1] * z[2] - y[2] * z[1];
		x[1] = -y[0] * z[2] + y[2] * z[0];
		x[2] =  y[0] * z[1] - y[1] * z[0];

		// recompute Y = Z cross X
		y[0] =  z[1] * x[2] - z[2] * x[1];
		y[1] = -z[0] * x[2] + z[2] * x[0];
		y[2] =  z[0] * x[1] - z[1] * x[0];
		
		// normalize X and Y vector
		mag = sqrtf(x[0] * x[0] + x[1] * x[1] + x[2] * x[2]);
		if (mag)
		{
			x[0] /= mag;
			x[1] /= mag;
			x[2] /= mag;
		}
		mag = sqrt(y[0] * y[0] + y[1] * y[1] + y[2] * y[2]);
		if (mag)
		{
			y[0] /= mag;
			y[1] /= mag;
			y[2] /= mag;
		}
		
		// build view matrix
		#define M(row,col)  m[col*4+row]
		M(0,0) = x[0];  M(0,1) = x[1];  M(0,2) = x[2];  M(0,3) = 0.0;
		M(1,0) = y[0];  M(1,1) = y[1];  M(1,2) = y[2];  M(1,3) = 0.0;
		M(2,0) = z[0];  M(2,1) = z[1];  M(2,2) = z[2];  M(2,3) = 0.0;
		M(3,0) = 0.0;   M(3,1) = 0.0;   M(3,2) = 0.0;   M(3,3) = 1.0;
		#undef M

		glMultMatrixf(m);
		glTranslated(-eyex, -eyey, -eyez);
	}
	void CCamera::reset()
	{
		m_eye = v3gen(0.0f, 0.0f, 0.0f);
		m_look = v3gen(0.0f, 0.0f, -1.0f);
		m_up = v3gen(0.0f, 1.0f, 0.0f);
		m_right = v3gen(1.0f, 0.0f, 0.0f);
	}
	void CCamera::build()
	{
		float m[16];
		
		m_look = v3nor(m_look);
		m_right = v3cross(m_look, m_up);
		m_right = v3nor(m_right);
		m_up = v3cross(m_right, m_look);
		m_up = v3nor(m_up);
		
		m[0] = m_right.x;
		m[1] = m_up.x;
		m[2] = -m_look.x;
		m[3] = 0.0f;
		
		m[4] = m_right.y;
		m[5] = m_up.y;
		m[6] = -m_look.y;
		m[7] = 0.0f;
		
		m[8] = m_right.z;
		m[9] = m_up.z;
		m[10] = -m_look.z;
		m[11] = 0.0f;
		
		m[12] = -v3dot(m_right, m_eye);
		m[13] = -v3dot(m_up, m_eye);
		m[14] = v3dot(m_look, m_eye);
		m[15] = 1.0f;
		
		glMatrixMode(GL_MODELVIEW);
		glMultMatrixf(m);
	}
	void CCamera::yaw(float ang)
	{
		
	}
	void CCamera::roll(float ang)
	{

	}
	void CCamera::pitch(float ang)
	{}
	void CCamera::walk(float dt)
	{
		m_eye = v3add(m_eye, v3mul(m_look, dt));
	}
	void CCamera::strafe(float dt)
	{
		m_eye = v3add(m_eye, v3mul(m_right, dt));
	}
	void CCamera::fly(float dt)
	{
		m_eye = v3add(m_eye, v3mul(m_up, dt));
	}
}